﻿/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.Reflection;
using System.Collections.Specialized;
using System.Collections;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace PickGold.Util.WordSpliter
{
	/// <summary>
	/// 分词器
	/// </summary>
	public partial class Spliter
	{
		//    const string PATTERNS = @"[０-９\d]+\%|[０-９\d]{1,2}月|[０-９\d]{1,2}日|[０-９\d]{1,4}年|" +
		//@"[０-９\d]{1,4}-[０-９\d]{1,2}-[０-９\d]{1,2}|" +
		//@"\s+|" +
		//@"[０-９\d]+|[^ａ-ｚＡ-Ｚa-zA-Z0-9０-９\u4e00-\u9fa5]|[ａ-ｚＡ-Ｚa-zA-Z]+|[\u4e00-\u9fa5]+";

		const string PATTERNS = @"([０-９\d]+)|([ａ-ｚＡ-Ｚa-zA-Z_]+)";

		internal Dictionary<string, string> Infinitives = null;

		internal WordDictionary Keywords = null;
		internal Delimiter Delimiters = null;
		internal Synonym Synonyms = null;
		internal Wildcard Wildcards = null;

		internal MatchOptions Options;
		internal MatchParameter Parameters;

		#region ctor

		/// <summary>
		/// 构造一分词器
		/// </summary>
		public Spliter() : this(null, null, null) { }

		/// <summary>
		/// 构造一分词器
		/// </summary>
		/// <param name="keywords">关键字</param>
		public Spliter(Keyword[] keywords) : this(keywords, null, null) { }

		/// <summary>
		/// 构造一分词器
		/// </summary>
		/// <param name="keywords">关键字</param>
		/// <param name="synonyms">别名</param>
		public Spliter(Keyword[] keywords, string[][] synonyms) : this(keywords, null, synonyms) { }

		/// <summary>
		/// 构造一分词器
		/// </summary>
		/// <param name="keywords">关键字</param>
		/// <param name="delimiters">分隔符</param>
		/// <param name="synonyms">别名</param>
		public Spliter(Keyword[] keywords, string[] delimiters, string[][] synonyms)
		{
			var sn = Surname();
			var ns = Prename(sn, sn, sn);
			var n0 = ns[0].ToCharArray();
			var n1 = ns[1].ToCharArray();
			var n2 = ns[2].ToCharArray();
			if (keywords == null)
				keywords = Reflector<Keyword>.EmptyArray;
			if (delimiters == null)
				delimiters = Delimiter();
			if (synonyms == null)
				synonyms = Reflector<string>.EmptyArray.MakeArray();
			this.FillKeywords(ref keywords);
			this.FillDelimiters(ref delimiters);
			this.FillSynonyms(ref synonyms);
			this.FillChinese(ref sn, ref n0, ref n1, ref n2);
			this.Keywords = new WordDictionary(keywords, new ChineseName(sn, n0, n1, n2));
			this.Delimiters = new Delimiter(delimiters);
			this.Synonyms = new Synonym(synonyms);
			this.Infinitives = Infinitive();
		}

		/// <summary>
		/// 填充关键字
		/// </summary>
		/// <param name="keywords">关键字</param>
		protected virtual void FillKeywords(ref Keyword[] keywords) { }

		/// <summary>
		/// 填充中文名
		/// </summary>
		/// <param name="surname">姓</param>
		/// <param name="mono">单名</param>
		/// <param name="middle">中间名</param>
		/// <param name="suffix">后缀名</param>
		protected virtual void FillChinese(ref string[] surname, ref char[] mono, ref char[] middle, ref char[] suffix) { }

		/// <summary>
		/// 填充分隔符
		/// </summary>
		/// <param name="delimiters">分隔符</param>
		protected virtual void FillDelimiters(ref string[] delimiters) { }

		/// <summary>
		/// 填充别名
		/// </summary>
		/// <param name="synonyms">别名</param>
		protected virtual void FillSynonyms(ref string[][] synonyms) { }

		/// <summary>
		/// 填充通配符
		/// </summary>
		/// <param name="wildcards">通配符</param>
		protected virtual void FillWildcards(ref string[] wildcards) { }

		private static Dictionary<string, string> Infinitive()
		{
			var dic = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			var xml = new XmlDocument();
			var ndn = MethodBase.GetCurrentMethod().Name;
			try
			{
				xml.Load(typeof(Spliter).GetManifestResourceStream(Mime.XML));
			}
			catch (Exception x)
			{
				x.SetLastError();
				return dic;
			}

			var nod = xml.DocumentElement.SelectSingleNode(ndn);
			if (nod == null)
				return dic;

			for (var i = nod.ChildNodes.Count - 1; i >= 0; i--)
			{
				var n = nod.ChildNodes[i];
				if (n.NodeType != XmlNodeType.Element || n.Attributes.Count < 2)
					continue;

				for (var ii = n.Attributes.Count - 1; ii >= 0; ii--)
				{
					if (!dic.ContainsKey(n.Attributes[ii].Value))
						dic.Add(n.Attributes[ii].Value, n.Name);
				}
			}
			return dic;
		}

		private static string[] Surname()
		{
			var xml = new XmlDocument();
			try
			{
				xml.Load(typeof(Spliter).GetManifestResourceStream(Mime.XML));
			}
			catch (Exception x)
			{
				x.SetLastError();
				return Reflector<string>.EmptyArray;
			}

			var nod = xml.DocumentElement.SelectSingleNode(MethodBase.GetCurrentMethod().Name);
			if (nod == null)
				return Reflector<string>.EmptyArray;

			var ls = new List<string>();
			for (var i = nod.ChildNodes.Count - 1; i >= 0; i--)
			{
				var n = nod.ChildNodes[i];
				if (n.NodeType == XmlNodeType.Element && !ls.Contains(n.Name))
					ls.Add(n.Name);
			}
			return ls.ToArray();
		}

		private static string[] Delimiter()
		{
			var xml = new XmlDocument();
			try
			{
				xml.Load(typeof(Spliter).GetManifestResourceStream(Mime.XML));
			}
			catch (Exception x)
			{
				x.SetLastError();
				return Reflector<string>.EmptyArray;
			}

			var nod = xml.DocumentElement.SelectSingleNode(MethodBase.GetCurrentMethod().Name);
			if (nod == null)
				return Reflector<string>.EmptyArray;

			var t = nod.InnerText;
			var ts = new string[t.Length];
			for (var i = t.Length - 1; i >= 0; i--)
				ts[i] = t[i].ToString();
			return ts;
		}

		private static string[] Prename(object mono, object middle, object suffix)
		{
			var m = MethodBase.GetCurrentMethod();
			var ps = m.GetParameters();
			var ns = new string[ps.Length];
			var xml = new XmlDocument();
			try
			{
				xml.Load(typeof(Spliter).GetManifestResourceStream(Mime.XML));
			}
			catch (Exception x)
			{
				x.SetLastError();
				for (var i = ps.Length - 1; i >= 0; i--)
					ns[i] = string.Empty;
				return ns;
			}

			var n = m.Name;
			var nod = xml.DocumentElement.SelectSingleNode(m.Name);
			if (nod == null)
			{
				for (var i = ps.Length - 1; i >= 0; i--)
					ns[i] = string.Empty;
				return ns;
			}

			for (var i = ps.Length - 1; i >= 0; i--)
			{
				var a = nod.Attributes[ps[i].Name];
				n = a != null ? a.Value : null;
				ns[i] = string.IsNullOrWhiteSpace(n) ? string.Empty : n;
			}
			return ns;
		}

		#endregion

		/*
		/// <summary>
		/// 合并英文专用词。
		/// 如果字典中有英文专用词如U.S.A, C++.C#等
		/// 需要对初步分词后的英文和字母进行合并
		/// </summary>
		/// <param name="words"></param>
		/// <param name="start"></param>
		/// <param name="end"></param>
		/// <returns></returns>
		private String MergeEnglishSpecialWord(CExtractWords extractWords, ArrayList words, int start, ref int end)
		{
			StringBuilder str = new StringBuilder();

			int i;

			for (i = start; i < words.Count; i++)
			{
				string word = (string)words[i];

				//word 为空或者为空格回车换行等分割符号，中断扫描
				if (word.Trim() == "")
				{
					break;
				}

				//如果遇到中文，中断扫描
				if (word[0] >= 0x4e00 && word[0] <= 0x9fa5)
				{
					break;
				}

				str.Append(word);
			}

			String mergeString = str.ToString();
			List<T_WordInfo> exWords = extractWords.ExtractFullText(mergeString);

			if (exWords.Count == 1)
			{
				T_WordInfo info = (T_WordInfo)exWords[0];
				if (info.Word.Length == mergeString.Length)
				{
					end = i;
					return mergeString;
				}
			}

			return null;

		}
		*/

		private bool MergeEnglishSpecialWord(string orginal, SuperLinkedList<Result> results, ref SuperLinkedListNode<Result> current)
		{
			var cur = current;

			cur = cur.Next;

			int last = -1;

			while (cur != null)
			{
				if (cur.Value.Type == ResultType.Symbol || cur.Value.Type == ResultType.English)
				{
					last = cur.Value.Position + cur.Value.Word.Length;
					cur = cur.Next;
				}
				else
				{
					break;
				}
			}


			if (last >= 0)
			{
				var first = current.Value.Position;

				var newWord = orginal.Substring(first, last - first);

				var wa = Keywords.GetKeyword(newWord);

				if (wa == null)
					return false;

				while (current != cur)
				{
					var removeItem = current;
					current = current.Next;
					results.Remove(removeItem);
				}

				var newWordInfo = new Result(new SearchMatch(first, last - first, wa), orginal, Parameters);

				newWordInfo.Type = ResultType.English;
				newWordInfo.Rank = Parameters.EnglishRank;

				if ((this.Options & MatchOptions.EnglishSegment) != MatchOptions.None)
				{
					var lowerWord = newWordInfo.Word.ToLower();

					if (lowerWord != newWordInfo.Word)
					{
						if (current == null)
							results.AddLast(newWordInfo);
						else
							results.AddBefore(current, newWordInfo);
					}

					newWordInfo = new Result(lowerWord, newWordInfo.Position, newWordInfo.Flags, newWordInfo.Frequency, Parameters.EnglishLowerRank, newWordInfo.Type, newWordInfo.Original);
				}
				else if ((this.Options & MatchOptions.IgnoreCapital) != MatchOptions.None)
				{
					newWordInfo.Word = newWordInfo.Word.ToLower();
				}

				if (current == null)
					results.AddLast(newWordInfo);
				else
					results.AddBefore(current, newWordInfo);

				return true;
			}


			return false;

		}

		private SuperLinkedList<Result> GetInitSplit(string text)
		{
			var result = new SuperLinkedList<Result>();

			var lexical = new Lexical(text);

			DFAResult dfaResult;

			for (var i = 0; i < text.Length; i++)
			{
				var c = text[i];

				dfaResult = lexical.Input(c, i);

				switch (dfaResult)
				{
					case DFAResult.Continue:
						continue;
					case DFAResult.Quit:
						result.AddLast(lexical.OutputToken);
						break;
					case DFAResult.ElseQuit:
						result.AddLast(lexical.OutputToken);
						if (lexical.OldState != 255)
						{
							i--;
						}

						break;
				}

			}

			dfaResult = lexical.Input(0, text.Length);

			switch (dfaResult)
			{
				case DFAResult.Continue:
					break;
				case DFAResult.Quit:
					result.AddLast(lexical.OutputToken);
					break;
				case DFAResult.ElseQuit:
					result.AddLast(lexical.OutputToken);
					break;
			}

			return result;
		}

		private string ConvertChineseCapitalToAsiic(string text)
		{
			StringBuilder sb = null;

			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				bool needReplace = false;

				//[０-９\d]+)|([ａ-ｚＡ-Ｚa-zA-Z_]+)";
				if (c >= '０' && text[i] <= '９')
				{
					c -= '０';
					c += '0';
					needReplace = true;
				}
				else if (c >= 'ａ' && text[i] <= 'ｚ')
				{
					c -= 'ａ';
					c += 'a';
					needReplace = true;
				}
				else if (c >= 'Ａ' && text[i] <= 'Ｚ')
				{
					c -= 'Ａ';
					c += 'A';
					needReplace = true;
				}

				if (needReplace)
				{
					if (sb == null)
					{
						sb = new StringBuilder();
						sb.Append(text.Substring(0, i));
					}
				}

				if (sb != null)
				{
					sb.Append(c);
				}

			}

			if (sb == null)
			{
				return text;
			}
			else
			{
				return sb.ToString();
			}
		}

		private string GetStem(string word)
		{
			var stem = word;
			if (Infinitives.TryGetValue(word, out stem))
				return stem;

			var s = new Stemmer();
			foreach (var ch in word)
			{
				if (char.IsLetter((char)ch))
					s.add(ch);
			}
			s.stem();
			return s.ToString();

		}

		private SuperLinkedList<Result> PreSplit(String text)
		{
			var result = GetInitSplit(text);

			var cur = result.First;

			while (cur != null)
			{
				if ((this.Options & MatchOptions.IgnoreSpace) != MatchOptions.None)
				{
					if (cur.Value.Type == ResultType.Space)
					{
						var lst = cur;
						cur = cur.Next;
						result.Remove(lst);
						continue;
					}
				}

				switch (cur.Value.Type)
				{
					case ResultType.SimplifiedChinese:

						var inputText = cur.Value.Word;

						var originalWordType = ResultType.SimplifiedChinese;

						//if (_Options.TraditionalChineseEnabled)
						//{
						//    string simplified = Microsoft.VisualBasic.Strings.StrConv(cur.Value.Word, Microsoft.VisualBasic.VbStrConv.SimplifiedChinese, 0);

						//    if (simplified != cur.Value.Word)
						//    {
						//        originalWordType = WordType.TraditionalChinese;
						//        inputText = simplified;
						//    }
						//}

						var pls = this.Keywords.GetAllMatchs(inputText, (this.Options & MatchOptions.ChineseNameIdentify) != MatchOptions.None);
						var chsMatch = new FullTextMatch(Keywords);
						chsMatch.Options = Options;
						chsMatch.Parameters = Parameters;
						var chsMatchWords = chsMatch.Match(pls.Items, cur.Value.Word, pls.Count);

						var curChsMatch = chsMatchWords.First;
						while (curChsMatch != null)
						{
							var wi = curChsMatch.Value;

							wi.Position += cur.Value.Position;
							wi.Original = originalWordType;
							wi.Type = originalWordType;

							//if (_Options.OutputSimplifiedTraditional)
							//{
							//    if (_Options.TraditionalChineseEnabled)
							//    {
							//        string newWord;
							//        WordType wt;

							//        if (originalWordType == WordType.SimplifiedChinese)
							//        {
							//            newWord = Microsoft.VisualBasic.Strings.StrConv(wi.Word, 
							//                Microsoft.VisualBasic.VbStrConv.TraditionalChinese, 0);
							//            wt = WordType.TraditionalChinese;
							//        }
							//        else
							//        {
							//            newWord = Microsoft.VisualBasic.Strings.StrConv(wi.Word, 
							//                Microsoft.VisualBasic.VbStrConv.SimplifiedChinese, 0);
							//            wt = WordType.SimplifiedChinese;
							//        }

							//        if (newWord != wi.Word)
							//        {
							//            WordInfo newWordInfo = new WordInfo(wi);
							//            newWordInfo.Word = newWord;
							//            newWordInfo.OriginalWordType = originalWordType;
							//            newWordInfo.WordType = wt;
							//            newWordInfo.Rank = _Parameters.SimplifiedTraditionalRank;
							//            newWordInfo.Position = wi.Position;
							//            chsMatchWords.AddBefore(curChsMatch, newWordInfo);
							//        }
							//    }
							//}

							curChsMatch = curChsMatch.Next;
						}

						var lst = result.AddAfter(cur, chsMatchWords);
						var removeItem = cur;
						cur = lst.Next;
						result.Remove(removeItem);
						break;
					case ResultType.English:
						cur.Value.Rank = Parameters.EnglishRank;
						cur.Value.Word = ConvertChineseCapitalToAsiic(cur.Value.Word);

						if ((this.Options & MatchOptions.EnglishSegment) != MatchOptions.None)
						{
							var lower = cur.Value.Word.ToLower();

							if (lower != cur.Value.Word)
							{
								result.AddBefore(cur, new Result(lower, cur.Value.Position, KeywordFlags.Foreign, 1,
									Parameters.EnglishLowerRank, ResultType.English, ResultType.English));
							}

							string stem = GetStem(lower);

							if (!string.IsNullOrEmpty(stem))
							{
								if (lower != stem)
								{
									result.AddBefore(cur, new Result(stem, cur.Value.Position, KeywordFlags.Foreign, 1,
										Parameters.EnglishStemRank, ResultType.English, ResultType.English));
								}
							}
						}
						else if ((this.Options & MatchOptions.IgnoreCapital) != MatchOptions.None)
						{
							cur.Value.Word = cur.Value.Word.ToLower();
						}

						if ((this.Options & MatchOptions.EnglishMultiDimensionality) != MatchOptions.None)
						{
							var needSplit = false;

							foreach (char c in cur.Value.Word)
							{
								if ((c >= '0' && c <= '9') || (c == '_'))
								{
									needSplit = true;
									break;
								}
							}

							if (needSplit)
							{
								var output = new List<string>();
								if (InnerRegex.GetMatchStrings(cur.Value.Word, PATTERNS, true, output))
								{
									var outputCount = 0;

									foreach (var str in output)
									{
										if (!string.IsNullOrEmpty(str))
										{
											outputCount++;
											if (outputCount > 1)
												break;
										}
									}


									if (outputCount > 1)
									{
										var position = cur.Value.Position;
										foreach (var splitWord in output)
										{
											if (string.IsNullOrEmpty(splitWord))
												continue;

											Result wi;

											if (splitWord[0] >= '0' && splitWord[0] <= '9')
											{
												wi = new Result(splitWord, KeywordFlags.Numeral, 1);
												wi.Position = position;
												wi.Rank = Parameters.NumericRank;
												wi.Original = ResultType.English;
												wi.Type = ResultType.Numeric;
											}
											else
											{
												wi = new Result(splitWord, KeywordFlags.Foreign, 1);
												wi.Position = position;
												wi.Rank = Parameters.EnglishRank;
												wi.Original = ResultType.English;
												wi.Type = ResultType.English;
											}

											result.AddBefore(cur, wi);
											position += splitWord.Length;
										}
									}
								}
							}
						}

						if (!this.MergeEnglishSpecialWord(text, result, ref cur))
							cur = cur.Next;
						break;
					case ResultType.Numeric:
						cur.Value.Word = this.ConvertChineseCapitalToAsiic(cur.Value.Word);
						cur.Value.Rank = this.Parameters == null ? 0 : this.Parameters.NumericRank;

						if (!this.MergeEnglishSpecialWord(text, result, ref cur))
							cur = cur.Next;
						//cur = cur.Next;
						break;
					case ResultType.Symbol:
						cur.Value.Rank = this.Parameters == null ? 0 : this.Parameters.SymbolRank;
						cur = cur.Next;
						break;
					default:
						cur = cur.Next;
						break;
				}

			}


			return result;

		}

		private void FilterStopWord(SuperLinkedList<Result> results)
		{
			if (results == null)
				return;

			var cur = results.First;
			while (cur != null)
			{
				if (Delimiters.IsDelimiter(cur.Value.Word,
					(this.Options & MatchOptions.FilterEnglish) != MatchOptions.None, Parameters.FilterEnglishLength,
					(this.Options & MatchOptions.FilterNumeric) != MatchOptions.None, Parameters.FilterNumericLength))
				{
					var removeItem = cur;
					cur = cur.Next;
					results.Remove(removeItem);
				}
				else
				{
					cur = cur.Next;
				}
			}
		}

		private void ProcessAfterSplit(string orginalText, SuperLinkedList<Result> results)
		{
			//匹配同义词
			if ((this.Options & MatchOptions.SynonymOutput) != MatchOptions.None)
			{
				var node = results.First;
				while (node != null)
				{
					var synonyms = Synonyms.GetSynonyms(node.Value.Word);
					if (synonyms != null)
					{
						foreach (var word in synonyms)
						{
							node = results.AddAfter(node, new Result(word, node.Value.Position,
								node.Value.Flags, node.Value.Frequency, Parameters.SymbolRank,
								ResultType.Synonym, node.Value.Type));
						}
					}

					node = node.Next;
				}
			}

			//通配符匹配
			if ((this.Options & MatchOptions.WildcardOutput) != MatchOptions.None)
			{
				var node = results.First;

				while (node != null)
				{
					var wildcards = this.Keywords.GetWildcards(node.Value.Word);

					if (wildcards.Count > 0)
					{
						for (var i = 0; i < wildcards.Count; i++)
						{
							var wildcardInfo = wildcards[i];
							var count = wildcardInfo.Segments.Count;
							if ((this.Options & MatchOptions.WildcardSegment) == MatchOptions.None)
								count = 1;
							for (var j = 0; j < count; j++)
							{
								var wi = wildcardInfo.Segments[j];

								if (wi.Word == node.Value.Word)
									continue;

								wi.Rank = Parameters.WildcardRank;
								wi.Position += node.Value.Position;
								results.AddBefore(node, wi);
							}
						}
					}

					node = node.Next;

					if (node != null)//过滤英文分词时多元分词重复输出的问题
					{
						if (node.Previous.Value.Word.ToLower() == node.Value.Word.ToLower())
							node = node.Next;
					}

				}
			}

			if ((this.Options & MatchOptions.CustomRule) != MatchOptions.None && this.Parameters != null && this.Parameters.CustomRule != null)//用户自定义规则
				this.Parameters.CustomRule(results, orginalText);
		}

		/// <summary>
		/// 分词
		/// </summary>
		/// <param name="text">输入文本</param>
		/// <returns>分词结果</returns>
		public ICollection<Result> Split(string text)
		{
			//return Split(text, MatchOptions.Default, null);
			return Split(text, MatchOptions.ChineseNameIdentify | MatchOptions.MultiDimensionality | MatchOptions.SynonymOutput | MatchOptions.UnknownWordIdentify | MatchOptions.WildcardOutput, null);
		}

		/// <summary>
		/// 分词
		/// </summary>
		/// <param name="text">输入文本</param>
		/// <param name="options">匹配选项：MatchOptions.ChineseNameIdentify | MatchOptions.MultiDimensionality | MatchOptions.SynonymOutput | MatchOptions.UnknownWordIdentify | MatchOptions.WildcardOutput</param>
		/// <returns>分词结果</returns>
		public ICollection<Result> Split(string text, MatchOptions options)
		{
			return Split(text, options, null);
		}

		/// <summary>
		/// 分词
		/// </summary>
		/// <param name="text">输入文本</param>
		/// <param name="options">匹配选项：MatchOptions.ChineseNameIdentify | MatchOptions.MultiDimensionality | MatchOptions.SynonymOutput | MatchOptions.UnknownWordIdentify | MatchOptions.WildcardOutput</param>
		/// <param name="parameters">匹配参数</param>
		/// <returns>分词结果</returns>
		public ICollection<Result> Split(string text, MatchOptions options, MatchParameter parameters)
		{
			if (string.IsNullOrEmpty(text))
				return new SuperLinkedList<Result>();

			this.Options = options;
			this.Parameters = parameters ?? new MatchParameter();

			var result = this.PreSplit(text);

			if ((this.Options & MatchOptions.FilterStopWords) != MatchOptions.None)
				this.FilterStopWord(result);
			this.ProcessAfterSplit(text, result);
			return result;
		}

		#region inner regex class

		static class InnerRegex
		{
			public static bool GetMatchStrings(string text, string regx, bool ignoreCase, List<string> output)
			{
				var begin = 0;
				var index = regx.IndexOf("(.+)");
				if (index < 0)
				{
					index = regx.IndexOf("(.+?)");
					if (index >= 0)
						begin = index + 5;
				}
				else
				{
					begin = index + 4;
				}
				if (index >= 0)
				{
					var t = regx.Substring(begin);
					if (GetMatch(text, t, ignoreCase) == string.Empty)
						return false;
				}

				var rf = RegexOptions.Singleline;
				if (ignoreCase)
					rf |= RegexOptions.IgnoreCase;
				var m = Regex.Matches(text, regx, rf);
				if (m.Count == 0)
					return false;

				output.Clear();
				for (var j = 0; j < m.Count; j++)
				{
					int count = m[j].Groups.Count;
					for (var i = 1; i < count; i++)
						output.Add(m[j].Groups[i].Value.Trim());
				}

				return true;

			}

			public static bool GetSingleMatchStrings(string text, string regx, bool ignoreCase, List<string> output)
			{
				var index = 0;
				var begin = 0;
				index = regx.IndexOf("(.+)");
				if (index < 0)
				{
					index = regx.IndexOf("(.+?)");
					if (index >= 0)
						begin = index + 5;
				}
				else
				{
					begin = index + 4;
				}
				if (index >= 0)
				{
					var endText = regx.Substring(begin);
					if (GetMatch(text, endText, ignoreCase) == "")
						return false;
				}

				var rf = RegexOptions.Singleline;
				if (ignoreCase)
					rf |= RegexOptions.IgnoreCase;
				var m = Regex.Matches(text, regx, rf);
				if (m.Count == 0)
					return false;

				output.Clear();
				for (var j = 0; j < m.Count; j++)
				{
					var count = m[j].Groups.Count;
					if (count > 0)
						output.Add(m[j].Groups[count - 1].Value.Trim());
				}
				return true;
			}

			public static bool GetSplitWithoutFirstStrings(string text, string regx, bool ignoreCase, ArrayList output)
			{
				if (output == null)
				{
					Debug.Assert(false);
					return false;
				}

				var rf = RegexOptions.Singleline;
				if (ignoreCase)
					rf |= RegexOptions.IgnoreCase;
				var strs = Regex.Split(text, regx, rf);
				if (strs == null || strs.Length <= 1)
					return false;

				output.Clear();
				for (var j = 1; j < strs.Length; j++)
					output.Add(strs[j]);
				return true;

			}

			public static string GetMatch(string text, string regx, bool ignoreCase)
			{
				var index = 0;
				var begin = 0;
				index = regx.IndexOf("(.+)");
				if (index < 0)
				{
					index = regx.IndexOf("(.+?)");
					if (index >= 0)
						begin = index + 5;
				}
				else
				{
					begin = index + 4;
				}

				if (index >= 0)
				{
					var endText = regx.Substring(begin);
					if (endText != string.Empty && GetMatch(text, endText, ignoreCase) == string.Empty)
						return string.Empty;
				}

				var rf = RegexOptions.Singleline;
				if (ignoreCase)
					rf |= RegexOptions.IgnoreCase;
				var ret = string.Empty;
				var m = Regex.Match(text, regx, rf);
				if (m.Groups.Count > 0)
					ret = m.Groups[m.Groups.Count - 1].Value;
				return ret;
			}

			public static string GetMatchSum(string text, string regx, bool ignoreCase)
			{
				var index = 0;
				var begin = 0;
				index = regx.IndexOf("(.+)");
				if (index < 0)
				{
					index = regx.IndexOf("(.+?)");
					if (index >= 0)
						begin = index + 5;
				}
				else
				{
					begin = index + 4;
				}

				if (index >= 0)
				{
					var endText = regx.Substring(begin);
					if (GetMatch(text, endText, ignoreCase) == "")
						return string.Empty;
				}

				var rf = RegexOptions.Singleline;
				if(ignoreCase)
					rf |= RegexOptions.IgnoreCase;
				var ret = string.Empty;
				var m = Regex.Match(text, regx, rf);
				for (var i = 1; i < m.Groups.Count; i++)
					ret += m.Groups[i].Value;
				return ret;
			}
		}

		#endregion
	}
}
